#include "HD44780Analyzer.h"
#include "HD44780AnalyzerSettings.h"
#include <AnalyzerChannelData.h>
#include <vector>
#include "PluginConstants.h"
#include "ProtocolFrameGrabber.h"

static const char* ANALYZER_NAME = "HD44780-V1.0.0.1";

HD44780Analyzer::HD44780Analyzer()
:	Analyzer(),  
	mSettings( new HD44780AnalyzerSettings() ),
	mSimulationInitilized( false )
{
	SetAnalyzerSettings( mSettings.get() );
    CreateFrameGrabbers();
}

HD44780Analyzer::~HD44780Analyzer()
{
    DeleteFrameGrabbers();
	KillThread();
}

void HD44780Analyzer::SetupResults()
{
	mResults.reset( new HD44780AnalyzerResults( this, mSettings.get() ) );
	SetAnalyzerResults( mResults.get() );
}

void HD44780Analyzer::InitializeThreadArtifacts()
{
    SetupResults();
    mResults->AddChannelBubblesWillAppearOn(  mSettings->GetClock() );
	mSampleRateHz = GetSampleRate();
    mClock = GetAnalyzerChannelData( mSettings->GetClock() );
	mData.clear();
	mDataMasks.clear();
    mDataChannels.clear();
    mFrameCounter = 1;
    mLastFrameCount = 0;
}

void HD44780Analyzer::GetChannelsToSample()
{
	U32 count = mSettings->GetDefinedChannelsCount();
    U32 channelCounter = 0;
	for( U32 i=0; i<count; i++ )
	{
		if( mSettings->GetDefinedChannel(i) != UNDEFINED_CHANNEL )
		{
            mChannelPos.push_back(i);
			mData.push_back( GetAnalyzerChannelData(  mSettings->GetDefinedChannel(i) ) );
			mDataMasks.push_back( 1 << channelCounter++ );
			mDataChannels.push_back( mSettings->GetDefinedChannel(i) );
		}
	}
}

void HD44780Analyzer::PositionClockAtCapturePoint()
{
    U64 PulseWidth = (mClock->GetSampleOfNextEdge() - mClock->GetSampleNumber());
    U64 Percentage= (U64)((double)PulseWidth * ((double)(mSettings->GetWhereToMeasurePulse()/100.0)));
    mClock->Advance( Percentage );
}

U64 HD44780Analyzer::CalculateDataFromChannels()
{
    U64 Result = 0;
    U32 NumDataLines = mData.size();
	for( U32 i=0; i< NumDataLines; i++ )
	{
        mData[i]->AdvanceToAbsPosition( mClock->GetSampleNumber() );
		if( mData[i]->GetBitState() == BIT_HIGH )
		{
			Result |= mDataMasks[i];
		}
	}	
    return Result;
}

void HD44780Analyzer::PositionStartMarkerOnChannels()
{
    U32 NumDataLines = mData.size();
	for( U32 i=0; i< NumDataLines; i++ )
	{
		mResults->AddMarker( mClock->GetSampleNumber(), AnalyzerResults::Start,   mSettings->GetDefinedChannel(mChannelPos[i]) );
	}
}

void HD44780Analyzer::PositionEndMarkerOnChannels()
{
    U32 NumDataLines = mData.size();
	for( U32 i=0; i< NumDataLines; i++ )
	{
		mResults->AddMarker( mClock->GetSampleNumber(), AnalyzerResults::Stop,   mSettings->GetDefinedChannel(mChannelPos[i]) );
	}
}

void HD44780Analyzer::PositionErrorMarkerOnChannels()
{
    U32 NumDataLines = mData.size();
	for( U32 i=0; i< NumDataLines; i++ )
	{
		mResults->AddMarker( mClock->GetSampleNumber(), AnalyzerResults::ErrorX ,   mSettings->GetDefinedChannel(mChannelPos[i]) );
	}
}

void HD44780Analyzer::PositionMarkerOnSingleFrameChannels()
{
    U32 NumDataLines = mData.size();
	for( U32 i=0; i< NumDataLines; i++ )
	{
        mResults->AddMarker( mClock->GetSampleNumber(), AnalyzerResults::One ,   mSettings->GetDefinedChannel(mChannelPos[i]) );
	}
}

bool HD44780Analyzer::MoveClockToNextTargetFrame()
{  
    mClock->AdvanceToNextEdge(); 
    return MoveClockToNextTargetFrameIfPossible();
}

bool HD44780Analyzer::MoveClockToNextTargetFrameIfPossible()
{
    bool Result = false;
    if ( mClock->DoMoreTransitionsExistInCurrentData() )
    {
		mClock->AdvanceToNextEdge();    
        Result = true;
    }
    return Result;
}


bool HD44780Analyzer::IsFrameWithinInitializationThreashold() 
{
    return mFrameCounter < INITIALIZATION_THREASHOLD ;
}

bool HD44780Analyzer::IsFrameAnInitializationCommand( U64 Data )
{
    return ( Data & 0X700 ) == 0X400 ;
}

bool HD44780Analyzer::IsFrameAFunctionSetCommand( U64 Data )
{
    return ( Data & 0x0E0) == 0x020;
}

bool HD44780Analyzer::IsFramePartOfInitializationSequence( U64 Data )
{
    //return (( Data & CMD_SET_MODE_11BITS ) == CMD_SET_MODE_11BITS) &&  (IsFrameWithinInitializationThreashold()) ) ? true : false;
    return ( IsFrameAnInitializationCommand(Data) && IsFrameAFunctionSetCommand(Data) && IsFrameWithinInitializationThreashold() );
}

void HD44780Analyzer::CreateFrameGrabbers()
{
    mFrameGenerators.push_back( new ProtocolFrameGrabber7Bits());
    mFrameGenerators.push_back( new ProtocolFrameGrabber8Bits());
    mFrameGenerators.push_back( new ProtocolFrameGrabber());
    StaticInitializationOfFrameGrabbers();
}

void HD44780Analyzer::DeleteFrameGrabbers()
{
    int Limit = mFrameGenerators.size();
    for ( int i=0; i < Limit; ++i )
    {
        delete mFrameGenerators[i];
    }
    mFrameGenerators.clear();
}

void HD44780Analyzer::StaticInitializationOfFrameGrabbers()
{
    int Limit = mFrameGenerators.size();
    for ( int i=0; i < Limit; ++i )
    {
        mFrameGenerators[i]->Init(this);
    }
}

void HD44780Analyzer::CaptureFrames()
{
    for( ; ; )
	{
        mFrameGenerators[mSettings->GetOperationMode()]->GrabFrame();
	}
}

void HD44780Analyzer::StoreFrame(  U64 Sample, U64 Data1, U64 Data2, U8 Flag , U8 FrameType)
{
    Frame NewFrame;
    NewFrame.mData1 = Data1;
    NewFrame.mData2 = Data2;
    NewFrame.mFlags = Flag;
    NewFrame.mType  = FrameType;
    NewFrame.mStartingSampleInclusive = Sample;
    NewFrame.mEndingSampleInclusive = mClock->GetSampleNumber();
    mFrameCounter++;
    mResults->AddFrame( NewFrame );
    mResults->CommitResults();
    ReportProgress( NewFrame.mEndingSampleInclusive );
}

void HD44780Analyzer::AdvanceClockToFirstRisingEdge()
{
    mClock->AdvanceToNextEdge();  
    if ( mClock->GetBitState() == BitState::BIT_LOW )
    {
        mClock->AdvanceToNextEdge();
    }
}

void HD44780Analyzer::WorkerThread()
{
    InitializeThreadArtifacts();
    GetChannelsToSample();
    AdvanceClockToFirstRisingEdge();
    CaptureFrames();
}

bool HD44780Analyzer::NeedsRerun()
{
	return false;
}

U32 HD44780Analyzer::GenerateSimulationData( U64 minimum_sample_index, U32 device_sample_rate, SimulationChannelDescriptor** simulation_channels )
{
	if( mSimulationInitilized == false )
	{
		mSimulationDataGenerator.Initialize( GetSimulationSampleRate(), mSettings.get() );
		mSimulationInitilized = true;
	}

	return mSimulationDataGenerator.GenerateSimulationData( minimum_sample_index, device_sample_rate, simulation_channels );
}

U32 HD44780Analyzer::GetMinimumSampleRateHz()
{
    return MINIMUN_SAMPLE_RATE_IN_HZ;
}

const char* HD44780Analyzer::GetAnalyzerName() const
{
	return ANALYZER_NAME;
}

const char* GetAnalyzerName()
{
	return ANALYZER_NAME;
}

Analyzer* CreateAnalyzer()
{
	return new HD44780Analyzer();
}

void DestroyAnalyzer( Analyzer* analyzer )
{
	delete analyzer;
}